﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using MinimalistFoodStreet.BackEnd.Infrastructure.Attributes;
using MinimalistFoodStreet.BackEnd.Infrastructure.Dtos.Request;
using MinimalistFoodStreet.BackEnd.Infrastructure.Dtos.Response;
using MinimalistFoodStreet.BackEnd.Infrastructure.EFCore;
using MinimalistFoodStreet.BackEnd.Infrastructure.Tools;
using MinimalistFoodStreet.BackEnd.Server.IServer;
using MinimalistFoodStreet.BackEnd.Server.Server.Tables;

namespace MinimalistFoodStreet.BackEnd.Server.Server
{
    [InjectClass]
    public class LoginServer : ILoginServer
    {
        private readonly ServerRepository _serverRepository;
        private readonly IConfiguration _configuration;
        private readonly IHttpContextAccessor _httpContextAccessor;

        public LoginServer(DbContext dbContext, IConfiguration configuration, IHttpContextAccessor httpContextAccessor)
        {
            _serverRepository = new ServerRepository(dbContext);
            _configuration = configuration;
            _httpContextAccessor = httpContextAccessor;
        }
        public Account CheckLogin(int aid, string code)
        {
            if (!_serverRepository.accountsEFCore.Query(d => d.AId == aid).Any())
            {
                return null;
            }
            var lastLog = _serverRepository.loginLogsEFCore.Query(d => d.LlAccountId == aid, false, d => d.LlCreateTime).FirstOrDefault();
            if (lastLog == null || lastLog.LlCode != code || lastLog.LlIp != _httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.ToString())
            {
                return null;
            }
            return _serverRepository.accountsEFCore.Query(d => d.AId == aid).Single();
        }

        public Administrator GetAdministrator(int aid)
        {
            return _serverRepository.administratorsEFCore.Query(d => d.AAccountId == aid).SingleOrDefault();
        }

        public Businesss GetBusiness(int aid)
        {
            return _serverRepository.businesssEFCore.Query(d => d.BAccountId == aid).SingleOrDefault();
        }

        public Supplier GetSupplier(int aid)
        {
            try
            {
                Supplier s = _serverRepository.suppliersEFCore.Query(d => d.SAccountId == aid).SingleOrDefault();
                return s;
            }
            catch (Exception e) {
                return null;
            }
        }

        public async Task<ResponseApiDto> LoginByAccount(RequestLoginDto dto, string endpoint)
        {
            // 确定账号存在
            if (!await _serverRepository.accountsEFCore.Query(d => d.AAccount == dto.account).AnyAsync())
            {
                return ResponseApiDto.Fail("账号或密码错误");
            }
            Account account = await _serverRepository.accountsEFCore.Query(d => d.AAccount == dto.account).SingleAsync();
            // 确定登录的端正确
            if (account.AEndpoint != endpoint)
            {
                return ResponseApiDto.Fail("账号或密码错误");
            }
            // 获取加密后的密码
            string encryptPassword = Encrypt.GetMd5Hash(dto.password + account.ASalt);
            // 确定密码正确
            if (account.APassword != encryptPassword)
            {
                return ResponseApiDto.Fail("账号或密码错误");
            }
            // 记录登陆日志
            string code = Tools.Guid_1();
            await _serverRepository.loginLogsEFCore.AddAsync(new LoginLog
            {
                LlAccountId = account.AId,
                LlCode = code,
                LlWay = "ByAccount",
                LlIp = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.ToString()
            });
            // 激活账号
            if (account.AIsActive == 0)
            {
                account.AIsActive = 1;
                await _serverRepository.accountsEFCore.UpdateAsync(account);
            }
            // 生成token并返回
            var jwtHelper = new JwtHelper(_configuration);
            string token = jwtHelper.CreateToken(new UserPayload { id = account.AId, code = code });
            return ResponseApiDto.Ok("登录成功", token);
        }

        public async Task<ResponseApiDto> LoginByPhone(RequestLoginDto dto, string endpoint)
        {
            // 确定电话号存在
            if (!await _serverRepository.accountsEFCore.Query(d => d.APhone == dto.phone).AnyAsync())
            {
                return ResponseApiDto.Fail("验证码错误");
            }
            Account account = await _serverRepository.accountsEFCore.Query(d => d.APhone == dto.phone).SingleAsync();
            // 确定登录的端正确
            if (account.AEndpoint != endpoint)
            {
                return ResponseApiDto.Fail("账号或密码错误");
            }
            // 确定验证码正确
            Varify lastVarify = await _serverRepository.varifysEFCore.Query(d => d.VPhone == dto.phone, false, d => d.VCreateTime).FirstOrDefaultAsync();
            if (lastVarify == null || lastVarify.VOutTime < DateTime.Now || lastVarify.VIsUsed != 0 || lastVarify.VCode != dto.captcha)
            {
                return ResponseApiDto.Fail("验证码错误");
            }
            string code = Tools.Guid_1();
            await _serverRepository.ExecuteInTransactionAsync(async () =>
            {
                // 将验证码设为已使用
                lastVarify.VIsUsed = 1;
                await _serverRepository.varifysEFCore.UpdateAsync(lastVarify);
                // 记录登陆日志
                await _serverRepository.loginLogsEFCore.AddAsync(new LoginLog
                {
                    LlAccountId = account.AId,
                    LlCode = code,
                    LlWay = "ByPhone",
                    LlIp = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.ToString()
                });
                // 激活账号
                if (account.AIsActive == 0)
                {
                    account.AIsActive = 1;
                    await _serverRepository.accountsEFCore.UpdateAsync(account);
                }
            }, () =>
            {
                // 执行完后会报错不会执行之后的代码
                return null;
            });
            // 生成token并返回
            var jwtHelper = new JwtHelper(_configuration);
            string token = jwtHelper.CreateToken(new UserPayload { id = account.AId, code = code });
            return ResponseApiDto.Ok("登录成功", token);
        }
    }
}
